/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Copyright 2002-2003 by Mark Wolgemuth, All rights reserved.             */
/* Copyright 2002-2003 by Employease, Inc.  All rights reserved.           */
/*                                                                         */
/* Redistribution and use in source and binary forms, with or without      */
/* modification, are permitted provided that the following conditions      */
/* are met:                                                                */
/*                                                                         */
/*    1. Redistributions of source code must retain the above copyright    */
/* notice, this list of conditions and the following disclaimer.           */
/*    2. Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the     */
/* documentation and/or other materials provided with the distribution.    */
/*                                                                         */
/* THIS SOFTWARE IS PROVIDED BY THE MOD_ATHENA PROJECT ``AS IS'' AND ANY   */
/* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE       */
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR      */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR        */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      */
/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT            */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "ath.h"

/* global lock array object */
static ath_lock _ath_locks[ATH_MUXS_HARDMAX];
static int _ath_mux_init_count = 0;

/* sets the path for lock
 * must set path before lock "exists" as lock
 * currently require reflected idx for path construction 
 */
void 
ath_lock_setpath(apr_pool_t *pool, ath_lock *lock, const char *prefix)
{
    char *suffix;
    char *fname;
    ASSERT(prefix);
    ASSERT(lock);
    ASSERT(lock->idx > -1);

    suffix = apr_psprintf(pool, "%d", lock->idx);
    fname = apr_pstrcat(pool, prefix, suffix, NULL);
    lock->path = fname;
}

/* create lock at index */
ath_lock * 
ath_lock_create(apr_pool_t *pool, ath_lock *lock)
{
    int result;
    int result_perm = APR_SUCCESS;
    ASSERT(lock);
    ASSERT(lock->path);

    /*  APR_LOCK_FCNTL   pick the default mechanism for the platform
     *  APR_LOCK_FLOCK   see ath.h
     *  APR_LOCK_SYSVSEM
     *  APR_LOCK_POSIXSEM
     *  APR_LOCK_PROC_PTHREAD 
     *  APR_LOCK_DEFAULT     
     */
    //result = ATH_GLOBAL_MUTEX_CREATE(&lock->mux, lock->path, pool);

    result = 
      apr_global_mutex_create(&lock->mux, lock->path, ath_lockmech, pool);

    if (result != APR_SUCCESS)
      {
	  ATH_APLOG(APLOG_EMERG, result, ATH_EMUXNCRE, lock->path, lock->mux);
	  exit(APEXIT_CHILDFATAL);
      }
    if (ath_lockmech == APR_LOCK_SYSVSEM)
	result_perm = unixd_set_global_mutex_perms(lock->mux);
    if (result_perm != APR_SUCCESS) 
      {
	  ATH_APLOG(APLOG_EMERG, result, ATH_EMUXPERM, lock->path, lock->mux);
	  exit(APEXIT_CHILDFATAL);
      }  
    return lock;
}


/* initialize lock at index (in child threads / procs startup) */
void 
ath_lock_init(apr_pool_t *pool, ath_lock *lock)
{
    int result;
    ASSERT(lock->path);
 
    result = apr_global_mutex_child_init(&lock->mux, lock->path, pool);
    if (result != APR_SUCCESS)
	ATH_APLOG(APLOG_EMERG, result, ATH_EMUXNINI, lock->path, lock->mux);
    if (lock->mux == NULL)
      {
	  ATH_APLOG(APLOG_STARTUP, 0, ATH_EMUXNULL, lock->path);
	  exit(APEXIT_CHILDFATAL);
      }
    _ath_mux_init_count++;
}


/* assumes lock has been created */
ath_lock * 
ath_lock_for_idx(int idx)
{
    ath_lock *lock = ath_lock_raw_for_idx(idx);
    ASSERT(lock->mux);
    return lock;
}

/* does not assume lock hsas been created */
ath_lock * 
ath_lock_raw_for_idx(int idx)
{
    ath_lock *lock;
    ASSERT(idx > -1);
    lock = &_ath_locks[idx];
    return lock;
}

void 
ath_lock_acquire(ath_lock *lock)
{
    int result;
    ASSERT(lock);
    result = apr_global_mutex_lock(lock->mux);
    if (result != APR_SUCCESS)
	ATH_APLOG(APLOG_WARNING, result, ATH_EMUXLOCK, lock->path, lock->mux);
}

void 
ath_lock_release(ath_lock *lock)
{
    int result;
    ASSERT(lock);
    result = apr_global_mutex_unlock(lock->mux);
    if (result != APR_SUCCESS)
	ATH_APLOG(APLOG_WARNING, result, ATH_EMUXUNLO, lock->path, lock->mux);
}

int
ath_lock_mux_init_count()
{
    return _ath_mux_init_count;
}
